import { action, observable } from "mobx";
import { History, Location } from 'history';
import { NavItem, RouteItem } from "../types";
import { IStore, User } from "@shared/types";
import { RoutesProvider } from "@admin/routes";

const lookUpParents = (item: NavItem, parents: NavItem[] = []): NavItem[] => {
    if (item.parent) {
        parents.push(item.parent);
        return lookUpParents(item.parent, parents);
    }
    return parents;
}

const lookUpVisibleParents = (item: NavItem, parents: NavItem[] = []): NavItem[] => {
    if (item.parent) {
        if (!item.parent.hidden) {
            parents.push(item.parent);
        }
        return lookUpVisibleParents(item.parent, parents);
    }
    return parents;
}

const prepareNavs = (items: NavItem[], parent?: NavItem, hidden?: boolean, mapFunc?: (item: NavItem) => void) => {
    const newItems: NavItem[] = [];
    for (let item of items) {
        const newItem = { ...item };
        newItem.parent = parent;
        newItem.parents = [];
        if (parent) {
            newItem.parents = lookUpParents(newItem);
        }
        if (hidden !== undefined) newItem.hidden = hidden;
        newItem.key = (newItem.key || newItem.url) || newItem.name;
        
        if (newItem.children && newItem.children.length > 0) {
            newItem.children = prepareNavs(newItem.children, newItem, false, mapFunc);
        }
        if (newItem.hiddens && newItem.hiddens.length > 0) {
            newItem.hiddens = prepareNavs(newItem.hiddens, newItem, true, mapFunc);
        }

        newItems.push(newItem);

        if (mapFunc) mapFunc(newItem);
    }
    return newItems;
}

const removeHiddenItem = (items: NavItem[]) => {
    for (let i = 0; i < items.length; i ++) {
        if (items[i].hidden) {
            items.splice(i, 1);
            i --;
        }
    }
}

export default class NavStore {

    @observable
    openNavKeys: string[] = [];

    @observable
    selectedNavKeys: string[] = [];

    currentNav: NavItem;

    items: NavItem[] = [];

    routes: RouteItem[] = [];

    navMap: Record<string, NavItem> = {};

    history: History;

    location: Location;

    store: IStore;

    constructor(store, history, location) {
        this.store = store;
        this.history = history;
        this.location = location;
    }

    setup(provider: RoutesProvider) {
        this.routes = provider.useRoutes(this.store.user);
        this.updateNavs(provider.useNavs(this.store.user));
    }

    updateNavs(items: NavItem[]) {
        let newItems = prepareNavs(items, undefined, undefined, item => {
            this.navMap[item.key!] = item;
        });
        removeHiddenItem(newItems);

        this.items = newItems;        
        this.refreshState(this.location);
    }

    @action
    navigate(navItemKey: string) {
        const navItem = this.navMap[navItemKey];
        if (!navItem || !navItem.url) return;

        this.history.push(navItem.url);
    }

    @action
    toggleNav(navItemKey: string, isOpen: boolean) {
        if (isOpen) {
            if (!this.openNavKeys.includes(navItemKey)) this.openNavKeys = [...this.openNavKeys, navItemKey];
        } else {
            let index = this.openNavKeys.indexOf(navItemKey);
            if (index >= 0) {
                let newOpenKeys = [...this.openNavKeys];
                newOpenKeys.splice(newOpenKeys.indexOf(navItemKey), 1);
                this.openNavKeys = newOpenKeys;
            }
        }
    }

    @action
    refreshState(location: Location) {
        this.location = location;

        if (this.items.length < 1) return;

        let url = location.pathname;
        
        let item: NavItem;
        if (!url || url === '/') {
            item = this.items[0];
        } else {
            let tUrl = url;
            if (tUrl.startsWith('/')) tUrl = tUrl.substring(1);
            item = this.navMap[url] || this.navMap[tUrl];
        }

        this.currentNav = item;
        if (item) {
            const { parents } = item;
            if (parents && parents.length > 0) {
                for (let parent of parents) {
                    if (parent.hidden) continue;
                    if (parent.children && parent.children.length > 0) {
                        this.toggleNav(parent.key!, true);
                    } else {
                        this.selectedNavKeys = [parent.key!];
                    }
                }
            }
            if (!item.hidden) {
                this.selectedNavKeys = [item.key!];
            }
        } else {
            this.selectedNavKeys = [];
        }
    }
}